import java.util.HashMap;
import java.util.Map;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.PropertiesCredentials;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodb.model.ListTablesRequest;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.model.AttributeAction;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
import com.amazonaws.services.dynamodbv2.model.ComparisonOperator;
import com.amazonaws.services.dynamodbv2.model.Condition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteItemRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteItemResult;
import com.amazonaws.services.dynamodbv2.model.DeleteTableRequest;
import com.amazonaws.services.dynamodbv2.model.DeleteTableResult;
import com.amazonaws.services.dynamodbv2.model.DescribeTableRequest;
import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
import com.amazonaws.services.dynamodbv2.model.GetItemResult;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ListTablesResult;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
import com.amazonaws.services.dynamodbv2.model.PutItemResult;
import com.amazonaws.services.dynamodbv2.model.QueryRequest;
import com.amazonaws.services.dynamodbv2.model.QueryResult;
import com.amazonaws.services.dynamodbv2.model.ReturnValue;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
import com.amazonaws.services.dynamodbv2.model.ScanRequest;
import com.amazonaws.services.dynamodbv2.model.ScanResult;
import com.amazonaws.services.dynamodbv2.model.TableDescription;
import com.amazonaws.services.dynamodbv2.model.UpdateItemRequest;
import com.amazonaws.services.dynamodbv2.model.UpdateItemResult;
import com.amazonaws.services.dynamodbv2.model.UpdateTableRequest;
import com.amazonaws.services.dynamodbv2.model.UpdateTableResult;
import com.amazonaws.services.dynamodbv2.util.Tables;

public class TestDynamoDB{
	   private static AmazonDynamoDBClient client;
	   	
	   private static void init() throws Exception {
	        AWSCredentials credentials = null;
	        try {
	            credentials = new PropertiesCredentials(TestDynamoDB.class.getResourceAsStream("AwsCredentials.properties"));
	        } catch (Exception e) {
	            throw new AmazonClientException(
	                    "Cannot load the credentials from the credential profiles file. " +
	                    "Please make sure that your credentials file is at the correct " +
	                    "location (~/.aws/credentials), and is in valid format.",
	                    e);
	        }
	        client = new AmazonDynamoDBClient(credentials);
	        Region usWest2 = Region.getRegion(Regions.US_WEST_2);
	        client.setRegion(usWest2);
	    }
	   
	   private static void CreateATable() throws Exception {
		   String tableName = "RawDataTable";
	       try {
	            // Create table if it does not exist yet
	            if (Tables.doesTableExist(client, tableName)) {
	                System.out.println("Table " + tableName + " is already ACTIVE");
	            } else {
	                // Create a table with a primary hash key named 'name', which holds a string
	            	CreateTableRequest createTableRequest = new CreateTableRequest().withTableName(tableName)
	                        .withKeySchema(new KeySchemaElement().withAttributeName("Airport_Terminal").withKeyType(KeyType.HASH), 
	                        			   new KeySchemaElement().withAttributeName("TimeStamp").withKeyType(KeyType.RANGE))
	                        .withAttributeDefinitions(new AttributeDefinition().withAttributeName("Airport_Terminal").withAttributeType(ScalarAttributeType.S), 
	                        						  new AttributeDefinition().withAttributeName("TimeStamp").withAttributeType(ScalarAttributeType.S))
	                        .withProvisionedThroughput(new ProvisionedThroughput().withReadCapacityUnits(1L).withWriteCapacityUnits(1L));
	                TableDescription createdTableDescription = client.createTable(createTableRequest).getTableDescription();
	                System.out.println("Created Table: " + createdTableDescription);

	                // Wait for it to become active
	                System.out.println("Waiting for " + tableName + " to become ACTIVE...");
	                Tables.waitForTableToBecomeActive(client, tableName);
	                    
	                // Describe our new table
	                DescribeTableRequest describeTableRequest = new DescribeTableRequest().withTableName(tableName);
	                TableDescription tableDescription = client.describeTable(describeTableRequest).getTable();
	                System.out.println("Table Description: " + tableDescription);
	            		}
	        } catch (AmazonServiceException ase) {
	            System.out.println("Caught an AmazonServiceException, which means your request made it "
	                    + "to AWS, but was rejected with an error response for some reason.");
	            System.out.println("Error Message:    " + ase.getMessage());
	            System.out.println("HTTP Status Code: " + ase.getStatusCode());
	            System.out.println("AWS Error Code:   " + ase.getErrorCode());
	            System.out.println("Error Type:       " + ase.getErrorType());
	            System.out.println("Request ID:       " + ase.getRequestId());
	        } catch (AmazonClientException ace) {
	            System.out.println("Caught an AmazonClientException, which means the client encountered "
	                    + "a serious internal problem while trying to communicate with AWS, "
	                    + "such as not being able to access the network.");
	            System.out.println("Error Message: " + ace.getMessage());
	        }
	   }
	   
	   private static void UpdateATable(){
		   String tableName = "RawDataTable";

		   ProvisionedThroughput provisionedThroughput = new ProvisionedThroughput()
		     .withReadCapacityUnits(1L)
		     .withWriteCapacityUnits(2L);

		   UpdateTableRequest updateTableRequest = new UpdateTableRequest()
		     .withTableName(tableName)
		     .withProvisionedThroughput(provisionedThroughput);

		   UpdateTableResult result = client.updateTable(updateTableRequest);
	   }
	   
	   private static void DeleteATable(){
		   String tableName = "sampleTable";

		   DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
		     .withTableName(tableName);
		   DeleteTableResult result = client.deleteTable(deleteTableRequest);
	   }
	   
//	   private static void ListTables(){
//		// Initial value for the first page of table names.
//		   String lastEvaluatedTableName = null;
//		   do {
//		       
//		       ListTablesRequest listTablesRequest = new ListTablesRequest()
//		       .withLimit(10)
//		       .withExclusiveStartTableName(lastEvaluatedTableName);
//		       
//		       ListTablesResult result = client.listTables(listTablesRequest);
//		       lastEvaluatedTableName = result.getLastEvaluatedTableName();
//		       
//		       for (String name : result.getTableNames()) {
//		           System.out.println(name);
//		       }
//		       
//		   } while (lastEvaluatedTableName != null);
//	   }
	   
	    
	   private static void AddAnItem(){
           String tableName = "RawDataTable";
		   // Add an item	            
           Map<String, AttributeValue> item = new HashMap<String, AttributeValue>();
           item.put("Airport_Terminal", new AttributeValue().withS("SLC_01"));
   		   item.put("TimeStamp", new AttributeValue().withS("06/24/2014 11:25:18"));
   		   item.put("BeaconID", new AttributeValue().withS("CP1P1.13567.21242"));
   		   item.put("DocumentID", new AttributeValue().withS("Doc_8"));
   		   item.put("EnergyPower", new AttributeValue().withS("86 dB"));
   		   item.put("TravelerID", new AttributeValue().withS("Traveler_09"));
   		   item.put("TravelerType", new AttributeValue().withS("First Class"));

           PutItemRequest putItemRequest = new PutItemRequest()
             .withTableName(tableName)
             .withItem(item);
           PutItemResult putItemResult = client.putItem(putItemRequest);
           System.out.println("Result: " + putItemResult);

           //Add another item
           item = new HashMap<String, AttributeValue>();
           item.put("Airport_Terminal", new AttributeValue().withS("SLC_02"));
   		   item.put("TimeStamp", new AttributeValue().withS("06/17/2014 14:09:37"));
   		   item.put("BeaconID", new AttributeValue().withS("CP4P2.10080.11202"));
   		   item.put("DocumentID", new AttributeValue().withS("Doc_9"));
   		   item.put("EnergyPower", new AttributeValue().withS("90 dB"));
   		   item.put("TravelerID", new AttributeValue().withS("Traveler_10"));
   		   item.put("TravelerType", new AttributeValue().withS("Economy Class"));

           putItemRequest = new PutItemRequest()
             .withTableName(tableName)
             .withItem(item);
           putItemResult = client.putItem(putItemRequest);
           System.out.println("Result: " + putItemResult);
	   }
	   
	   private static void GetAnItem(){
		   String tableName = "RawDataTable";
		   HashMap<String, AttributeValue> key = new HashMap<String, AttributeValue>();
		   key.put("Airport_Terminal", new AttributeValue().withS("SEA_01"));
		   key.put("TimeStamp", new AttributeValue().withS("06/25/2014 9:15:00"));

		   GetItemRequest getItemRequest = new GetItemRequest()
		       .withTableName(tableName)
		       .withKey(key);
		   GetItemResult result = client.getItem(getItemRequest);
		   Map<String, AttributeValue> map = result.getItem();
		   System.out.println(map);
	   }
	   
	   private static void UpdateAnItem(){
		   
		   String tableName = "RawDataTable";
		   Map<String, AttributeValueUpdate> updateItems = new HashMap<String, AttributeValueUpdate>();

		   HashMap<String, AttributeValue> key = new HashMap<String, AttributeValue>();
		   key.put("Airport_Terminal", new AttributeValue().withS("SEA_01"));
		   key.put("TimeStamp", new AttributeValue().withS("06/25/2014 9:15:00"));

		   // Add two new authors to the list.
//		   updateItems.put("Authors", 
//		     new AttributeValueUpdate()
//		       .withAction(AttributeAction.ADD)
//		       .withValue(new AttributeValue().withSS("AuthorYY", "AuthorZZ")));
		    
		   // Reduce the price. To add or subtract a value,
		   // use ADD with a positive or negative number.
//		   updateItems.put("Price", 
//		     new AttributeValueUpdate()
//		       .withAction(AttributeAction.ADD)
//		       .withValue(new AttributeValue().withN("-1")));
		              
		   // Delete the ISBN attribute.
//		   updateItems.put("TimeStamp", 
//		     new AttributeValueUpdate()
//		       .withAction(AttributeAction.DELETE));
		   
		   // Change the value of TravelerType attribute.
		   updateItems.put("TravelerType", 
		     new AttributeValueUpdate()
			   .withAction(AttributeAction.PUT)
			   .withValue(new AttributeValue().withS("Economy Class")));
		               
		   UpdateItemRequest updateItemRequest = new UpdateItemRequest()
		     .withTableName(tableName)
		     .withKey(key).withReturnValues(ReturnValue.UPDATED_NEW)
		     .withAttributeUpdates(updateItems);
		               
		   UpdateItemResult result = client.updateItem(updateItemRequest);
	   }
	   
	   private static void DeleteAnItem(){
		   String tableName = "RawDataTable";
		   HashMap<String, AttributeValue> key = new HashMap<String, AttributeValue> ();
		   key.put("Airport_Terminal", new AttributeValue().withS("SFO_01"));
		   key.put("TimeStamp", new AttributeValue().withS("06/26/2014 15:00:00"));
		         	
		   DeleteItemRequest deleteItemRequest = new DeleteItemRequest()
		       .withTableName(tableName)
		       .withKey(key);
		         	
		   DeleteItemResult deleteItemResult = client.deleteItem(deleteItemRequest);
	   }
	   
//	   private static void QueryATable(){
//		   Condition hashKeyCondition = new Condition()
//		    .withComparisonOperator(ComparisonOperator.EQ)
//		    .withAttributeValueList(new AttributeValue().withS("Airport_Terminal"));
//		   Condition rangeKeyCondition = new Condition()
//		    .withComparisonOperator(ComparisonOperator.EQ)
//		    .withAttributeValueList(new AttributeValue().withS("TimeStamp"));
//
//		   Map<String, Condition> keyConditions = new HashMap<String, Condition>();
//		   keyConditions.put("Airport_Terminal", hashKeyCondition);
//		   keyConditions.put("TimeStamp", rangeKeyCondition);
//
//		   QueryRequest queryRequest = new QueryRequest()
//		    .withTableName("RawDataTable")
//		    .withKeyConditions(keyConditions);
//
//		   QueryResult result = client.query(queryRequest);
//		   for (Map<String, AttributeValue> item : result.getItems()) {
//			   printItem(item);
//		   }
//	   }

	   private static void printItem(Map<String, AttributeValue> attributeList) {
		// TODO Auto-generated method stub
		        for (Map.Entry<String, AttributeValue> item : attributeList.entrySet()) {
		            String attributeName = item.getKey();
		            AttributeValue value = item.getValue();
		            System.out.println(attributeName + " "
		                    + (value.getS() == null ? "" : "S=[" + value.getS() + "]")
		                    + (value.getN() == null ? "" : "N=[" + value.getN() + "]")
		                    + (value.getB() == null ? "" : "B=[" + value.getB() + "]")
		                    + (value.getSS() == null ? "" : "SS=[" + value.getSS() + "]")
		                    + (value.getNS() == null ? "" : "NS=[" + value.getNS() + "]")
		                    + (value.getBS() == null ? "" : "BS=[" + value.getBS() + "] \n"));
		        }
		}

	public static void main(String[] args) throws Exception {
	        init(); 
	        //CreateATable();
	        //UpdateATable();
//	        DeleteATable();
	        //ListTables();  // PROBLEM!!!!!
	        AddAnItem();
	        //GetAnItem();
	        //UpdateAnItem();
	        //DeleteAnItem();
	        //QueryATable();
	   }            

	            // Scan items for movies with a year attribute greater than 1985
//	            HashMap<String, Condition> scanFilter = new HashMap<String, Condition>();
//	            Condition condition = new Condition()
//	                .withComparisonOperator(ComparisonOperator.GT.toString())
//	                .withAttributeValueList(new AttributeValue().withN("1985"));
//	            scanFilter.put("year", condition);
//	            ScanRequest scanRequest = new ScanRequest(tableName).withScanFilter(scanFilter);
//	            ScanResult scanResult = client.scan(scanRequest);
//	            System.out.println("Result: " + scanResult);
}

